import json
import requests
import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
                             QWidget, QPushButton, QTextEdit, QLabel, QMessageBox)
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QFont
from datetime import datetime, timedelta

class DataFetcher(QThread):
    """数据获取线程"""
    finished = pyqtSignal(bool, str)
    progress = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.headers = {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,ar;q=0.7",
            "cache-control": "no-cache",
            "origin": "https://xuangutong.com.cn",
            "pragma": "no-cache",
            "priority": "u=1, i",
            "referer": "https://xuangutong.com.cn/dingpan",
            "sec-ch-ua": "\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Microsoft Edge\";v=\"138\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "cross-site",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
        }
        self.url = "https://flash-api.xuangubao.com.cn/api/pool/detail"
        self.params = {"pool_name": "limit_up"}

    def is_st_stock(self, name):
        """判断是否为ST股票"""
        return name.upper().startswith('ST') or name.upper().startswith('*ST')

    def get_last_working_days(self, count):
        """获取最近的工作日，返回日期列表（倒序）"""
        working_days = []
        current_date = datetime.now()
        delta = timedelta(days=1)

        while len(working_days) < count:
            current_date -= delta
            if current_date.weekday() < 5:  # Monday to Friday are considered working days (0-4)
                working_days.append(current_date.strftime("%Y-%m-%d"))

        return working_days

    def run(self):
        try:
            all_limit_up_data = []
            self.progress.emit("正在获取数据...")

            # 获取最近 4 个工作日的日期
            last_working_days = self.get_last_working_days(4)

            for date in last_working_days:
                self.params["date"] = date
                response = requests.get(self.url, headers=self.headers, params=self.params)
                response.raise_for_status()

                self.progress.emit(f"正在解析 {date} 的数据...")
                data = response.json()

                if not data or "data" not in data or not data["data"]:
                    continue

                # 保存原始 JSON 数据
                with open(f"原始数据_{date}.json", "w", encoding="utf-8") as json_file:
                    json.dump(data["data"], json_file, ensure_ascii=False, indent=4)

                all_limit_up_data.append(data["data"])

            plate_count = {}
            limit_up_numbers = []
            limit_up_reasons = {}

            # 创建板块索引
            for limit_up_data in all_limit_up_data:
                for item in limit_up_data:
                    if self.is_st_stock(item.get("stock_chi_name", "")):
                        continue

                    limit_up_days = item.get("limit_up_days", 0)  # 获取今日涨停次数
                    related_plates = item.get("surge_reason", {}).get("related_plates", [])
                    for plate in related_plates:
                        plate_name = plate.get("plate_name", "")
                        if plate_name and plate_name != "ST股":
                            if plate_name in plate_count:
                                plate_count[plate_name]['count'] += 1
                                plate_count[plate_name]['limit_up_days'] += limit_up_days  # 累加涨停次数
                            else:
                                plate_count[plate_name] = {'count': 1, 'limit_up_days': limit_up_days}  # 初始化

            # 确保 normal_plates 被定义
            # 过滤出只在今日有涨停的板块
            hot_plates = [plate for plate in plate_count.keys() if plate_count[plate]['limit_up_days'] > 0]
            remaining_plates = [plate for plate in plate_count.keys() if plate_count[plate]['limit_up_days'] == 0]

            # 根据今日涨停次数排序
            hot_plates.sort(key=lambda x: plate_count[x]['limit_up_days'], reverse=True)

            # 将 "其他" 置于最后
            remaining_plates = [plate for plate in remaining_plates if plate != "其他"]
            remaining_plates.append("其他")  # 确保 "其他" 在最后

            # 合并排序好的板块列表，今日有涨停的在前，其他在后
            normal_plates = hot_plates + remaining_plates

            # 生成板块到索引的映射
            plate_to_index = {plate: idx + 1 for idx, plate in enumerate(normal_plates)}

            # 处理每只股票数据
            for day_offset, limit_up_data in enumerate(all_limit_up_data):
                for item in limit_up_data:
                    if self.is_st_stock(item.get("stock_chi_name", "")):
                        continue

                    raw_symbol = item.get("symbol", "")
                    symbol = raw_symbol.split('.')[0] if raw_symbol else ""

                    related_plates = item.get("surge_reason", {}).get("related_plates", [])
                    plate_indices = []

                    # 收集板块索引
                    for plate in related_plates:
                        plate_name = plate.get("plate_name", "")
                        if plate_name in plate_to_index:
                            plate_indices.append(plate_to_index[plate_name])

                    if plate_indices:
                        indices_str = '.'.join(map(str, plate_indices))
                        limit_up_numbers.append((symbol, indices_str))

                        reasons_str = ' '.join(plate.get("plate_name", "") for plate in related_plates)

                        # 添加倒数天数标记
                        if day_offset > 0:
                            reasons_str += f" (+{day_offset})"

                        # 记录每只股票的涨停理由
                        if symbol not in limit_up_reasons:
                            limit_up_reasons[symbol] = reasons_str
                        else:
                            # 只更新为最近的理由
                            continue

            # 建立最终的涨停理由
            final_limit_up_reasons = []
            for symbol, reason in limit_up_reasons.items():
                final_limit_up_reasons.append((symbol, reason))

            # 保存涨停数字到txt文件
            with open("涨停数字.txt", "w", encoding="gbk") as f:
                for symbol, indices in limit_up_numbers:
                    f.write(f"{symbol}\t{indices}\n")

            # 保存涨停理由到文件
            with open("涨停理由.txt", "w", encoding="gbk") as f:
                for symbol, reason in final_limit_up_reasons:
                    f.write(f"{symbol}\t{reason}\n")

            # 保存板块索引到文件
            with open("板块索引.txt", "w", encoding="gbk") as f:
                for i, plate_name in enumerate(normal_plates, 1):
                    f.write(f"{i}\t{plate_name}\n")

            # 统计信息
            stats_info = f"共获取{len(all_limit_up_data)}天数据.\n包含{len(limit_up_numbers)}只涨停股票.\n"
            with open("统计信息.txt", "w", encoding="gbk") as f:
                f.write(stats_info)

            success_msg = f"数据获取成功！共处理了 {len(limit_up_numbers)} 只涨停股票（已排除ST股票）"
            self.finished.emit(True, success_msg)

        except requests.exceptions.RequestException as e:
            self.finished.emit(False, f"请求失败：{e}")
        except json.JSONDecodeError as e:
            self.finished.emit(False, f"JSON解析失败：{e}")
        except Exception as e:
            self.finished.emit(False, f"发生错误：{e}")

class StockAnalyzer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.data_fetcher = None

    def initUI(self):
        self.setWindowTitle('股票涨停数据分析器')
        self.setGeometry(100, 100, 1200, 800)

        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # 创建主布局
        main_layout = QVBoxLayout()
        central_widget.setLayout(main_layout)

        # 创建顶部按钮区域
        top_layout = QHBoxLayout()

        # 获取数据按钮
        self.fetch_btn = QPushButton('获取涨停数据')
        self.fetch_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 10px;
                font-size: 14px;
                font-weight: bold;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)
        self.fetch_btn.clicked.connect(self.fetch_data)
        top_layout.addWidget(self.fetch_btn)

        # 添加弹性空间
        top_layout.addStretch()

        main_layout.addLayout(top_layout)

        # 创建中部按钮区域
        middle_layout = QHBoxLayout()

        # 查看按钮
        self.view_numbers_btn = QPushButton('查看涨停数字')
        self.view_reasons_btn = QPushButton('查看涨停理由')
        self.view_plates_btn = QPushButton('查看板块索引')

        # 设置按钮样式
        button_style = """
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 8px 16px;
                font-size: 12px;
                border-radius: 4px;
                margin: 2px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
            QPushButton:pressed {
                background-color: #1565C0;
            }
            QPushButton:disabled {
                background-color: #CCCCCC;
                color: #666666;
            }
        """

        self.view_numbers_btn.setStyleSheet(button_style)
        self.view_reasons_btn.setStyleSheet(button_style)
        self.view_plates_btn.setStyleSheet(button_style)

        # 初始状态禁用查看按钮
        self.view_numbers_btn.setEnabled(False)
        self.view_reasons_btn.setEnabled(False)
        self.view_plates_btn.setEnabled(False)

        # 连接按钮事件
        self.view_numbers_btn.clicked.connect(lambda: self.view_file('涨停数字.txt'))
        self.view_reasons_btn.clicked.connect(lambda: self.view_file('涨停理由.txt'))
        self.view_plates_btn.clicked.connect(lambda: self.view_file('板块索引.txt'))

        middle_layout.addWidget(self.view_numbers_btn)
        middle_layout.addWidget(self.view_reasons_btn)
        middle_layout.addWidget(self.view_plates_btn)
        middle_layout.addStretch()

        main_layout.addLayout(middle_layout)

        # 创建文本显示区域
        self.text_display = QTextEdit()
        self.text_display.setFont(QFont("Courier New", 10))
        self.text_display.setReadOnly(True)
        self.text_display.setStyleSheet("""
            QTextEdit {
                background-color: #f5f5f5;
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px;
            }
        """)
        self.text_display.setPlainText("请先获取数据，然后点击查看按钮来查看不同类型的数据...")

        main_layout.addWidget(self.text_display)

        # 创建状态栏
        self.status_label = QLabel('就绪')
        self.status_label.setStyleSheet("""
            QLabel {
                background-color: #f0f0f0;
                border: 1px solid #ccc;
                padding: 5px;
                border-radius: 3px;
            }
        """)
        main_layout.addWidget(self.status_label)

        # 设置窗口居中
        self.center()

    def center(self):
        """窗口居中"""
        screen = QApplication.desktop().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)

    def fetch_data(self):
        """获取数据"""
        self.fetch_btn.setEnabled(False)
        self.fetch_btn.setText('正在获取数据...')

        # 禁用查看按钮
        self.view_numbers_btn.setEnabled(False)
        self.view_reasons_btn.setEnabled(False)
        self.view_plates_btn.setEnabled(False)

        # 创建并启动数据获取线程
        self.data_fetcher = DataFetcher()
        self.data_fetcher.progress.connect(self.update_status)
        self.data_fetcher.finished.connect(self.on_data_fetched)
        self.data_fetcher.start()

    def update_status(self, message):
        """更新状态"""
        self.status_label.setText(message)

    def on_data_fetched(self, success, message):
        """数据获取完成"""
        self.fetch_btn.setEnabled(True)
        self.fetch_btn.setText('获取涨停数据')

        if success:
            self.status_label.setText(message)
            # 启用查看按钮
            self.view_numbers_btn.setEnabled(True)
            self.view_reasons_btn.setEnabled(True)
            self.view_plates_btn.setEnabled(True)

            # 显示成功消息
            QMessageBox.information(self, '成功',
                                    message + '\n\n文件已保存：\n- 涨停数字.txt\n- 涨停理由.txt\n- 板块索引.txt\n- 统计信息.txt')

            # 默认显示涨停数字
            self.view_file('涨停数字.txt')
        else:
            self.status_label.setText(f'错误: {message}')
            QMessageBox.critical(self, '错误', message)

    def view_file(self, filename):
        """查看文件内容"""
        try:
            if not os.path.exists(filename):
                QMessageBox.warning(self, '警告', f'文件 {filename} 不存在，请先获取数据')
                return

            with open(filename, 'r', encoding='gbk') as f:
                content = f.read()

            title = f"========== {filename} ==========\n\n"
            self.text_display.setPlainText(title + content)

            # 更新状态
            self.status_label.setText(f'正在查看: {filename}')

            # 移动光标到顶部
            cursor = self.text_display.textCursor()
            cursor.movePosition(cursor.Start)
            self.text_display.setTextCursor(cursor)

        except Exception as e:
            QMessageBox.critical(self, '错误', f'读取文件失败: {e}')
            self.status_label.setText(f'读取文件失败: {e}')

def main():
    app = QApplication(sys.argv)

    # 设置应用程序样式
    app.setStyleSheet("""
        QMainWindow {
            background-color: #f0f0f0;
        }
        QWidget {
            font-family: "微软雅黑", "Arial", sans-serif;
        }
    """)

    analyzer = StockAnalyzer()
    analyzer.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()